package com.zxj.camerademo.camera1;

import android.app.Activity;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class CameraHelper implements Camera.PreviewCallback {

    private static final String TAG = CameraHelper.class.getCanonicalName();
    private Activity mActivity;
    private SurfaceView mSurfaceView;//用于预览的SurfaceView对象
    private int picWidth = 2160;        //保存图片的宽
    private int picHeight = 3840;       //保存图片的高
    private Camera mCamera;             //Camera对象
    private Camera.Parameters mParameters; //Camera对象的参数
    public SurfaceHolder mSurfaceHolder;                   //SurfaceHolder对象
    public int mCameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;  //摄像头方向
    public int mDisplayOrientation;    //预览旋转的角度
    private CallBack mCallBack;   //自定义的回调

    public CameraHelper(Activity activity, SurfaceView surfaceView){
        this.mActivity = activity;
        this.mSurfaceView = surfaceView;
        mSurfaceHolder = mSurfaceView.getHolder();
        init();
    }

    private void init() {
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                if (mCamera == null) {
                    openCamera(mCameraFacing);//打开相机
                }
                startPreview();//开始预览
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                releaseCamera();//释放相机资源
            }
        });
    }

    public boolean openCamera(int cameraFacing){
        boolean supportCameraFacing = supportCameraFacing(cameraFacing);//判断手机是否支持前置/后置摄像头
        if(supportCameraFacing){
            try {
                mCamera = Camera.open(cameraFacing);
                initParameters(mCamera);    //初始化相机配置信息
                mCamera.setPreviewCallback(this);
            }catch (Exception e){
                Toast.makeText(mActivity,"打开相机失败!",Toast.LENGTH_SHORT).show();
                e.printStackTrace();
                return false;
            }
        }
        return supportCameraFacing;
    }


    //配置相机参数
    private void initParameters(Camera camera) {
        try {
            mParameters = camera.getParameters();
            mParameters.setPreviewFormat(ImageFormat.NV21);//设置预览图片的格式

            //获取与指定宽高相等或最接近的尺寸
            //设置预览尺寸
            Camera.Size bestPreviewSize = getBestSize(mSurfaceView.getWidth(), mSurfaceView.getHeight(), mParameters.getSupportedPreviewSizes());
            mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);

            //设置保存图片尺寸
            Camera.Size bestPicSize = getBestSize(picWidth, picHeight, mParameters.getSupportedPreviewSizes());
            mParameters.setPictureSize(bestPicSize.width, bestPicSize.height);

            //对焦模式
            if (isSupportFocus(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
                mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            if(isSupportFocus(Camera.Parameters.FOCUS_MODE_AUTO)){
                mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            }

            camera.setParameters(mParameters);
        }catch (Exception e){
            Toast.makeText(mActivity,"相机初始化失败!",Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }

    //开始预览
    public void startPreview() {
        try {
            mCamera.setPreviewDisplay(mSurfaceHolder);//设置相机预览对象
            setCameraDisplayOrientation(mActivity);//设置预览时相机旋转的
            mCamera.startPreview();
            startFaceDetect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void startFaceDetect() {
        mCamera.startFaceDetection();//开始人脸检测
        //当开始人脸检测时开始回调
        mCamera.setFaceDetectionListener(new Camera.FaceDetectionListener() {
            /**
             * @param faces 代表检测到的人脸,是一个Face数组(画面内可能存在多张人脸)
             * @param camera
             */
            @Override
            public void onFaceDetection(Camera.Face[] faces, Camera camera) {
                if(mCallBack != null){
                    mCallBack.onFaceDetect(transForm(faces));
                    Log.d(TAG,"检测到 "+faces.length+" 张人脸");
                }
            }
        });
    }

    //释放相机
    public void releaseCamera() {
        if (mCamera != null) {
//             mCamera.stopFaceDetection();
            mCamera.stopPreview();
            mCamera.setPreviewCallback(null);
            mCamera.release();
            mCamera = null;
        }
    }

    //切换摄像头
    public void exchangeCamera() {
        releaseCamera();
        if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK){
            mCameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT;
        }else {
            mCameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
        }
        Log.d(TAG,"mCameraFacing:"+mCameraFacing);
        openCamera(mCameraFacing);
        startPreview();
    }

    //将相机中用于表示人脸矩形的坐标转换成UI页面的坐标
    private ArrayList<RectF> transForm(Camera.Face[] faces) {
        Matrix matrix =new Matrix();
        // Need mirror for front camera.
        boolean mirror = (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT);
        matrix.setScale(mirror ?-1f:1f,1f);
        // This is the value for android.hardware.Camera.setDisplayOrientation.
        matrix.postRotate(mDisplayOrientation);
        // Camera driver coordinates range from (-1000, -1000) to (1000, 1000).
        // UI coordinates range from (0, 0) to (width, height).
        matrix.postScale(mSurfaceView.getWidth() / 2000f, mSurfaceView.getHeight() / 2000f);
        matrix.postTranslate(mSurfaceView.getWidth() / 2f, mSurfaceView.getHeight() / 2f);

        ArrayList<RectF> rectList = new ArrayList<>();
        for (Camera.Face face : faces) {
            Log.e(TAG,"检测到的人脸的可信度:"+face.score);
            RectF srcRect = new RectF(face.rect);
            RectF dstRect = new RectF(0f, 0f, 0f, 0f);
            matrix.mapRect(dstRect,srcRect);
            rectList.add(dstRect);
        }

        return rectList;
    }

    //设置预览旋转的角度
    private void setCameraDisplayOrientation(Activity activity) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(mCameraFacing, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

        int screenDegree = 0;
        switch (rotation){
            case Surface.ROTATION_0:
                screenDegree = 0;
                break;
            case Surface.ROTATION_90:
                screenDegree = 90;
                break;
            case Surface.ROTATION_180:
                screenDegree = 180;
                break;
            case Surface.ROTATION_270:
                screenDegree = 270;
                break;
        }

        //根据前置与后置摄像头的不同，设置预览方向，否则会发生预览图像倒过来的情况。
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            mDisplayOrientation = (info.orientation + screenDegree) % 360;
            mDisplayOrientation = (360 - mDisplayOrientation) % 360;          // compensate the mirror
        } else {
            mDisplayOrientation = (info.orientation - screenDegree + 360) % 360;
        }
        mCamera.setDisplayOrientation(mDisplayOrientation);

        Log.d(TAG,"屏幕的旋转角度 : "+rotation);
        Log.d(TAG,"setDisplayOrientation(result) : "+mDisplayOrientation);
    }


    //获取与指定宽高相等或最接近的尺寸
    private Camera.Size getBestSize(int targetWidth,int targetHeight,List<Camera.Size> sizeList) {
        Camera.Size bestSize = null;
        double targetRatio = (targetHeight / targetWidth);  //目标大小的宽高比
        double minDiff = targetRatio;

        for (Camera.Size size : sizeList) {
            double supportedRatio = (size.width / size.height);
            Log.d(TAG,"系统支持的尺寸 : "+size.width+"* "+size.height+" ,  比例"+supportedRatio);
        }

        for (Camera.Size size : sizeList) {
            if (size.width == targetHeight && size.height == targetWidth) {
                bestSize = size;
                break;
            }
            double supportedRatio = (size.width / size.height);
            if (Math.abs(supportedRatio - targetRatio) < minDiff) {
                minDiff = Math.abs(supportedRatio - targetRatio);
                bestSize = size;
            }

        }
        Log.d(TAG,"目标尺寸 ："+targetWidth+" * "+targetHeight+" ，   比例  "+targetRatio);
        Log.d(TAG,"最优尺寸 ："+bestSize.height+" * "+bestSize.width);
        return bestSize;
    }

    //判断是否支持某个相机
    private boolean supportCameraFacing(int cameraFacing) {
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        int numberOfCameras = Camera.getNumberOfCameras();
        for(int i=0;i<numberOfCameras;i++){
            Camera.getCameraInfo(i,cameraInfo);
            if(cameraInfo.facing == cameraFacing){
                return true;
            }
        }
        return false;
    }

    //判断是否支持某一对焦模式
    private boolean isSupportFocus(String focusMode) {
        boolean autoFocus = false;
        List<String> listFocusMode = mParameters.getSupportedFocusModes();
        for (String mode : listFocusMode) {
            if (mode == focusMode)
                autoFocus = true;
            Log.d(TAG,"相机支持的对焦模式： "+mode);
        }
        return autoFocus;
    }

    public Camera getCamera(){
        return mCamera;
    }

    public void takePic(){
        /**
         * 拍照时通过调用Camera的takePicture()方法来完成的
         * takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg)
         *
         * 1.ShutterCallback shutter：在拍照的瞬间被回调，这里通常可以播放"咔嚓"这样的拍照音效。
         * 2.PictureCallback raw：返回未经压缩的图像数据。
         * 3.PictureCallback postview：返回postview类型的图像数据
         * 4.PictureCallback jpeg：返回经过JPEG压缩的图像数据。
         */
        mCamera.takePicture(null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                mCamera.startPreview();
                mCallBack.onTakePic(data);
            }
        });
    }

    /**
     * 通过onPreviewFrame方法来获取到相机预览的数据，第一个参数data，就是相机预览到的原始数据
     * @param data
     * @param camera
     */
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        if(mCallBack != null){
            mCallBack.onPreviewFrame(data);
        }
    }

    interface CallBack {
        void onPreviewFrame(byte[] data);
        void onTakePic(byte[] data);
        void onFaceDetect(ArrayList<RectF> faces);
    }

    public void addCallBack(CallBack callBack){
        this.mCallBack = callBack;
    }
}
